home *** CD-ROM | disk | FTP | other *** search
/ IRIX Installation Tools & Overlays 2001 November / SGI IRIX Installation Tools & Overlays 2001 November - Disc 1.iso / dist / roboinst.idb / usr / etc / roboinst.z / roboinst
Text File  |  2001-10-10  |  15KB  |  675 lines

  1. #! /usr/bin/perl
  2. #Tag 0x00000f00
  3. #ident "$Revision $"
  4.  
  5. # Copyright 1997-2000, Silicon Graphics, Inc.
  6. # All Rights Reserved.
  7. #
  8. # This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  9. # the contents of this file may not be disclosed to third parties, copied or
  10. # duplicated in any form, in whole or in part, without the prior written
  11. # permission of Silicon Graphics, Inc.
  12. #
  13. # RESTRICTED RIGHTS LEGEND:
  14. # Use, duplication or disclosure by the Government is subject to restrictions
  15. # as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  16. # and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  17. # successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  18. # rights reserved under the Copyright Laws of the United States.
  19.  
  20. # roboinst
  21. #
  22. # starts the automatic installation process on each of the hosts listed on
  23. # the command line.  If no host is specified, automatic installation is
  24. # started on the current host.
  25.  
  26. # Initialization
  27.  
  28. $TMPDIR = $ENV{'TMPDIR'} || '/usr/tmp';
  29.  
  30. $ENV{'PATH'} = "/sbin:/usr/bin:/usr/bsd:/usr/sbin:/etc:/usr/etc:";
  31.  
  32. @dirs = split(/\//,$0);
  33. $O = "$dirs[$#dirs]";
  34.  
  35. $VERSION = "1";
  36.  
  37. $CONFIGARGS = "/etc/config/roboinst.options";
  38. $GETHOSTBYNAME = "/usr/etc/gethostbyname";
  39. $ROBOSTART = "/usr/etc/roboinst_start";
  40. $ID = "/usr/bin/id";
  41. $CONFIGDEF = "/usr/local/boot/roboinst/custom/";
  42. $SPOOLDIR = "/var/adm/roboinst";
  43. $HOSTFILE = "$SPOOLDIR/hosts.dat";
  44. $RSH = "/usr/bsd/rsh";
  45. $HOSTCHK = "/usr/etc/roboinst_check";
  46.  
  47. if (open(ARGS,"<$CONFIGARGS")) {
  48.     $_ = <ARGS>;
  49.     close(ARGS);
  50.     @ARGV = (split, @ARGV);
  51. }
  52.  
  53. $HOSTMAX = -1;
  54. $HOSTCNT = 0;
  55. $HOSTERR = "";
  56.  
  57. # parse command line
  58.  
  59. $usage =
  60.     "usage: ${O} [ -Llmnqrs ] [ -P disk ] [ -b bootdir ] [ -c configdir ]\n\t\t[ -f distribution ] [ -F selectionsfile ] [ -t time ] [ -N mode ] host ...\n";
  61.  
  62. require 'getopts.pl';        # fancy option parsing
  63.  
  64. if (! &Getopts('b:c:df:F:g:lLm:nN:pP:qrs:t:y')) {
  65.     die $usage;
  66. }
  67.  
  68. if (defined $opt_s) {
  69.     $RSH = $opt_s;
  70. }
  71.  
  72. if (defined $opt_l) {
  73.     &list_output();
  74.     exit(0);
  75. }
  76.  
  77. if (defined $opt_q) {
  78.     &list_queue();
  79.     exit(0);
  80. }
  81.  
  82. if (defined $opt_r) {
  83.     &job_remove();
  84.     exit(0);
  85. }
  86.  
  87. # beginning of normal processing
  88.  
  89. unless (defined $opt_b || defined $opt_L) {
  90.     die $usage;
  91. }
  92.  
  93. unless (defined $opt_n || defined $opt_y || defined $opt_t) {
  94.     warn "${O}: no time specified, running in test mode (-n)\n";
  95.     print STDERR "${O}: specify -y to override test mode\n";
  96. }
  97.  
  98. # set up arguments for remote roboinst_start command
  99.  
  100. if (defined $opt_t) {
  101.     if ($opt_t eq "now") {    # if time is now...
  102.     $timestr = "";
  103.     } else {            # otherwise...
  104.     $timestr = "-t \"$opt_t\"";
  105.     }
  106.     $yesnostr = (defined $opt_n ? "-n" : "-y"); # queue it!
  107. } else {
  108.     $timestr =  "";
  109.     $yesnostr = (defined $opt_y ? "-y" : "-n");
  110. }
  111. $debugstr = (defined $opt_d ? "-d" : "");
  112. if (defined $opt_P) {
  113.     if ($opt_P =~ /[()]/) {
  114.     $partitionstr = "-P \"$opt_P\"";
  115.     } else {
  116.     $partitionstr = "-P $opt_P";
  117.     }
  118. } elsif (defined $opt_p) {
  119.     $partitionstr = "-p";
  120. }
  121. $gracestr = (defined $opt_g ? "-g$opt_g" : "");
  122.  
  123. chop($Hostname = `hostname`);
  124. $Hostip = &getipaddr($Hostname);
  125. chop($Cwd = `pwd`);
  126.  
  127. $livestr = "";
  128. if (defined $opt_L) {
  129.     $livestr = "-L";
  130.     $timestr = "-t now" unless $timestr; # make sure job gets submitted
  131.     $bootstr = "";
  132. } elsif (defined $opt_b) {
  133.     ($bootserver,$bootdir) = &configdir_parse($opt_b);
  134.     unless ($bootdir) {
  135.     die "${O}: directory not specified in -b $opt_b\n";
  136.     }
  137.     if (! $bootserver) {
  138.     $bootserver = $Hostname; # default to localhost
  139.     }
  140.     $bootdir = "${bootserver}:$bootdir";
  141.     $bootstr = "-b $bootdir";
  142. }
  143.  
  144. ($configserver,$configdir) = &configdir_parse($opt_c);
  145. unless ($configdir) {
  146.     $configdir = $CONFIGDEF;
  147. }
  148. if ($configserver) {
  149.     $configip = &getipaddr($configserver);
  150. } else {
  151.     $configserver = $Hostname;
  152.     $configip = $Hostip;    # default to localhost
  153. }
  154. if (defined $opt_N) {
  155.     if ($opt_N !~ /local|none|bootp|1533|dhcp/i) {
  156.     die "usage: -N [dhcp|bootp1533|local]";
  157.     }
  158.     print STDERR "using \U$opt_N\E for ip address and network info\n"
  159.       if ($opt_d);
  160.     $netmodestr = "-N $opt_N";
  161. } else {
  162.     $netmodestr = "";
  163. }
  164. $configstr = "-c ${configip}:$configdir";
  165.  
  166. if (defined $opt_f) {
  167.     ($instserver,$instdir) = &configdir_parse($opt_f);
  168.     unless ($instdir) {
  169.     die "${O}: directory not specified in -f $opt_f\n";
  170.     }
  171.     $instuser = "";
  172.     if ($instserver) {
  173.     if ($instserver =~ m/^(.+@)(.+)$/) { # see if user@host
  174.         $instuser = $1;    # user@
  175.         $instserver = $2;    # host
  176.     }
  177.     $instip = &getipaddr($instserver);
  178.     } else {
  179.     $instip = $Hostip;
  180.     }
  181.     if ($instip eq $Hostip) {
  182.     unless (-r $instdir) {
  183.         die "${O}: distribution does not exist (-f $instdir)\n";
  184.     } elsif (substr($instdir,0,1) ne "/") {
  185.         $instdir = "$Cwd/$instdir";
  186.     }
  187.     }
  188.     $instargs = "-I default -f $instuser${instip}:$instdir ";
  189.     print STDERR "${O}: inst -a $instargs\n"
  190.     if (defined $opt_d);
  191. }
  192. if (defined $opt_F) {
  193.     ($instserver,$instdir) = &configdir_parse($opt_F);
  194.     unless ($instdir) {
  195.     die "${O}: filename not specified in -F $opt_F\n";
  196.     }
  197.     $instuser = "";
  198.     if ($instserver) {
  199.     if ($instserver =~ m/^(.+@)(.+)$/) { # see if user@host
  200.         $instuser = $1;    # user@
  201.         $instserver = $2;    # host
  202.     }
  203.     $instip = &getipaddr($instserver);
  204.     } else {
  205.     $instip = $Hostip;
  206.     }
  207.     if ($instip eq $Hostip) {
  208.     unless (-r $instdir) {
  209.         die "${O}: selections file does not exist (-F $instdir)\n";
  210.     } elsif (substr($instdir,0,1) ne "/") {
  211.         $instdir = "$Cwd/$instdir";
  212.     }
  213.     }
  214.     $instargs .= "-F $instuser${instip}:$instdir ";
  215.  
  216.     print STDERR "${O}: inst -a $instargs\n"
  217.     if (defined $opt_d);
  218. }
  219. $emailstr = "";
  220. if (defined $opt_m) {
  221.     $emailstr = "-m $opt_m";
  222. }
  223.  
  224. if (defined $instargs) {
  225.     $instcmd = "inst -a ";
  226.     if ($yesnostr ne "-y") {
  227.     $instcmd .= "-n ";
  228.     }
  229.     $instcmd .= $instargs;
  230. }
  231.  
  232. $roboinst_command =
  233.     "$ROBOSTART -z $yesnostr $debugstr $gracestr $livestr $netmodestr $partitionstr $bootstr $configstr $timestr $emailstr";
  234.  
  235. # If we are passing any of the new options (-N, -e), test also to see if a
  236. # current version of roboinst_start is installed.
  237. if ($netmodestr || $emailstr) {
  238.     $teststr = "test -x $ROBOSTART && $ROBOSTART -V 1.1 >/dev/null 2>&1";
  239. } else {
  240.     $teststr = "test -x $ROBOSTART";
  241. }
  242.  
  243. if ($instcmd) {
  244.     $roboinst_command =
  245.     "/bin/sh -c 'if ( $teststr ) || $instcmd ; then $roboinst_command ; else echo roboinst install failed ; fi'";
  246. } else {
  247.     $roboinst_command =
  248.     "/bin/sh -c 'if $teststr ; then $roboinst_command; else  echo \"roboinst not installed, use -f to specify installation directory\"; fi'";
  249. }
  250.  
  251. print STDERR $roboinst_command,"\n"
  252.     if (defined $opt_d);
  253.  
  254. if ($#ARGV == -1) {
  255.     if ($> != 0) {
  256.     die "${0}: Must be root to start installation\n";
  257.     }
  258.     chop($host = `hostname`);
  259.  
  260.     &job_submit($host,($roboinst_command));
  261. }
  262.  
  263. while ($#ARGV >= 0) {
  264.     $host = $ARGV[0];
  265.     shift @ARGV;
  266.  
  267.     @command = ($RSH, $host, "-l", "root", "-n", $roboinst_command);
  268.  
  269.     &job_submit($host,@command);
  270. }
  271.  
  272. exit(0);            # success?
  273.  
  274. #
  275. # ---- end of main processing ----
  276. #
  277.  
  278. # getipaddr - return the IP address for a given host ($1)
  279.  
  280. sub getipaddr {
  281.     local($hostname) = @_;
  282.  
  283.     if (! -x $GETHOSTBYNAME) {
  284.     die "${O}: $GETHOSTBYNAME not installed, aborting\n";
  285.     }
  286.  
  287.     local($addr) = `$GETHOSTBYNAME $hostname | \
  288.     nawk -v a=0 '/^$hostname / { a=\$3; exit }
  289.         END      { print a }'`;
  290.     chop $addr;
  291.  
  292.     die "${O}: unable to convert $hostname to an IP address\n"
  293.     if ($addr eq "0");
  294.  
  295.     return $addr;
  296. }
  297.  
  298. # result_print
  299. #
  300. # display result of remote command
  301.  
  302. sub result_print {
  303.     local($host,$message) = @_;
  304.  
  305.     local(@lines) = split(/\n/,$message);
  306.  
  307.     foreach (@lines) {
  308.     print "${host}: $_\n";
  309.     }
  310. }
  311.  
  312. # result_save
  313. #
  314. # remember job number for possible remove (-r)
  315.  
  316. sub result_save {
  317.     local($host,$message) = @_;
  318.  
  319.     local(@lines) = split(/\n/,$message);
  320.  
  321.     foreach (@lines) {
  322.     if (m/job \S+ at/) {
  323.         local($jobinfo) = "${host}: $_";
  324.  
  325.         &job_save($host,$jobinfo);
  326.         last;
  327.     }
  328.     }
  329. }
  330.  
  331. # job_save
  332. #
  333. # save job number to file, by ip address
  334.  
  335. sub job_save {
  336.     local($hostname,$jobnum) = @_;
  337.  
  338.     if (! -d $SPOOLDIR) {
  339.     $result = `mkdir -p $SPOOLDIR 2>&1`;
  340.     if (! -d $SPOOLDIR) {
  341.         &result_print("${O}",$result);
  342.         return;
  343.     }
  344.     }
  345.  
  346.     local($hostip) = &getipaddr($hostname);
  347.  
  348.     if (open(SPOOL,">$SPOOLDIR/$hostip")) {
  349.     print SPOOL $jobnum,"\n";
  350.     close(SPOOL);
  351.     } else {
  352.     warn "${O}: unable to write queue file $SPOOLDIR/$hostip\n";
  353.     }
  354. }
  355.  
  356. # job_read
  357. #
  358. # get job number from file, by ip address
  359.  
  360. sub job_read {
  361.     local($hostname) = @_;
  362.  
  363.     if (! -d $SPOOLDIR) {
  364.     warn "${O}: no queue directory $SPOOLDIR, job number not available\n";
  365.     return "";
  366.     }
  367.  
  368.     local($hostip) = &getipaddr($hostname);
  369.  
  370.     if (open(SPOOL,"<$SPOOLDIR/$hostip")) {
  371.     local($line) = <SPOOL>;
  372.     close(SPOOL);
  373.     if ($line =~ m/job \S+ at/) {
  374.         return $line;
  375.     }
  376.     warn "${O}: invalid queue file $SPOOLDIR/$hostip, job number not available\n";
  377.     } else {
  378.     warn "${O}: no queue file $SPOOLDIR/$hostip for $host\n";
  379.     }
  380.     return "";
  381. }
  382.  
  383. # job_clear
  384. #
  385. # clear job number file (ip address)
  386.  
  387. sub job_clear {
  388.     local($hostname) = @_;
  389.  
  390.     return unless (-d $SPOOLDIR);
  391.  
  392.     local($hostip) = &getipaddr($hostname);
  393.  
  394.     unlink "$SPOOLDIR/$hostip";
  395. }
  396.  
  397. # list_queue
  398. #
  399. # list the jobs in the queue directory
  400.  
  401. sub list_queue {
  402.     opendir(DIR,$SPOOLDIR) ||
  403.     die "${O}: no queue directory $SPOOLDIR\n";
  404.  
  405.     local(@files);
  406.  
  407.     local($file);
  408.     while (defined ($file = readdir(DIR))) {
  409.     print STDERR $file,"\n" if ($opt_d);
  410.     next if ($file eq "." || $file eq "..");
  411.  
  412.     push(@files,$file);
  413.     }
  414.  
  415.     close(DIR);
  416.  
  417.     foreach $file (sort @files) {
  418.     if (open(SPOOL,"<$SPOOLDIR/$file")) {
  419.         print $_ while (<SPOOL>);
  420.         close(SPOOL);
  421.     }
  422.     }
  423. }
  424.  
  425. # configdir_parse
  426. #
  427. # parse configdir string
  428.  
  429. sub configdir_parse {
  430.     local($str) = @_;
  431.     local($hostname,$path);
  432.  
  433.     if ($str =~ m/^(\S*):(\S*)$/i) {
  434.     $hostname = $1;
  435.     $path = $2;
  436.     } else {
  437.     $hostname = "";
  438.     $path = $str;
  439.     }
  440.     return ($hostname,$path);
  441. }
  442.  
  443. # list output from host
  444.  
  445. sub list_output {
  446.  
  447.     local($exp) = "";
  448.  
  449.     while ($#ARGV >= 0) {
  450.     $host = $ARGV[0];
  451.     shift @ARGV;
  452.  
  453.     if ($exp ne "") {
  454.         $exp .= "|";
  455.     }
  456.     $exp .= $host;
  457.     }
  458.  
  459.     open(LOG,"</var/adm/SYSLOG") ||
  460.     die "${O}: unable to read /var/adm/SYSLOG\n";
  461.  
  462.     while (<LOG>) {
  463.     if (m/^\S+\s+\S+\s+\S+\s+[0-9][A-Z]:($exp)/o) {
  464.         print $_;
  465.     }
  466.     }
  467.  
  468.     close(LOG);
  469. }
  470.  
  471. # remove (cancel) job
  472.  
  473. sub job_remove {
  474.  
  475.     while ($#ARGV >= 0) {
  476.     $host = $ARGV[0];
  477.     shift @ARGV;
  478.  
  479.     local($jobinfo) = &job_read($host);
  480.  
  481.     next unless ($jobinfo =~ m/job (\S+) at/);
  482.     local($jobnum) = $1;
  483.  
  484.     print "${O}: cancelling job $jobnum on $host\n";
  485.  
  486.     $result = `$RSH $host -l root at -r $jobnum 2>&1`;
  487.     &result_print($host,$result);
  488.  
  489.     if ($result eq "") {
  490.         &job_clear($host);
  491.     }
  492.     }
  493. }
  494.  
  495. # check given hostname to make sure it isn't a required server
  496.  
  497. sub is_server {
  498.     local($hostname) = @_;
  499.     local($hostip) = &getipaddr($hostname);
  500.  
  501.     local($bootip) = &getipaddr($bootserver);
  502.     if ($hostip eq $bootip) {
  503.     warn "${O}: cannot install on bootserver ($bootserver)\n";
  504.     return 1;
  505.     }
  506.  
  507.     if ($hostip eq $configip) {
  508.     warn "${O}: cannot install on configserver ($configserver)\n";
  509.     return 1;
  510.     }
  511.  
  512.     return 0;
  513. }
  514.  
  515. # submit job
  516.  
  517. sub job_submit {
  518.     local($hostname,@cmd) = @_;
  519.     local($pid);
  520.  
  521.     # do not submit job if this is a server machine (unless we're live)
  522.  
  523.     return unless ($opt_L || ! &is_server($hostname));
  524.  
  525.     print "${O}: submitting job on $hostname\n";
  526.  
  527.     if (($pid = open(JOB, "-|")) == 0) {
  528.     exec @cmd;
  529.     } elsif ($pid > 0) {
  530.     local($result) = "";
  531.     while (<JOB>) {
  532.         if (m/roboinst: PROMIFADDR -z (.*)/) {
  533.         local($chaddr) = $1;
  534.         print STDERR "${O}: $hostname has hardware address $chaddr\n"
  535.             if ($opt_d);
  536.         &host_check($hostname,$chaddr);
  537.         next;        # do not echo this return code
  538.         }
  539.  
  540.         $result .= $_;
  541.         &result_print($hostname,$_);
  542.     }
  543.     close(JOB);
  544.  
  545.     &result_save($hostname,$result);
  546.  
  547.     } else {
  548.     print "${O}: unable to submit job on ${hostname}\: $!\n";
  549.     }
  550. }
  551.  
  552. # host_check
  553.  
  554. sub host_check {
  555.     local($hostname,$chaddr) = @_;
  556.  
  557.     print STDERR "${O}: looking up $hostname ($chaddr)\n"
  558.     if ($opt_d);
  559.  
  560.     if (! -d $SPOOLDIR) {
  561.     $result = `mkdir -p $SPOOLDIR 2>&1`;
  562.     if (! -d $SPOOLDIR) {
  563.         &result_print("${O}",$result);
  564.     }
  565.     }
  566.  
  567.     local($newfile) = "$HOSTFILE\.new";
  568.     local($output) = 0;
  569.  
  570.     if (open(NADDRS,">$newfile")) {
  571.     $output = 1;
  572.     }
  573.  
  574.     local($found) = 0;
  575.     local($count) = 0;
  576.     if (open(ADDRS,"<$HOSTFILE")) {
  577.     while (<ADDRS>) {
  578.         chop;
  579.         next unless m/(\S+)\s(\S+)$/;
  580.         $count++;
  581.         if ($1 eq $chaddr) {
  582.         $found = $count;
  583.         print NADDRS "$1 $hostname\n" if ($output);
  584.         } else {
  585.         print NADDRS "$1 $2\n" if ($output);
  586.         }
  587.     }
  588.     close(ADDRS);
  589.     }
  590.     if ($found == 0) {
  591.     print NADDRS "$chaddr $hostname\n" if ($output);
  592.     $found = ++$count;
  593.     }
  594.  
  595.     if ($output) {
  596.     close(NADDRS);
  597.     rename($newfile,$HOSTFILE);
  598.     }
  599.  
  600.     local($count) = $found;
  601.  
  602.     if ($HOSTMAX >= 0 && $count > $HOSTMAX) {
  603.     &license_error();
  604.     } elsif ($count > $HOSTCNT) {
  605.     if (-x $HOSTCHK) {
  606.         $HOSTERR = `$HOSTCHK $count 2>&1`;
  607.         local(@lines) = split(/\n/,$HOSTERR);
  608.         $HOSTERR = "";
  609.         local($retcnt) = 0;
  610.         foreach (@lines) {
  611.         if (m/^roboinst: HOSTCNT (\d+)$/) {
  612.             $retcnt = int($1);
  613.         } else {
  614.             $HOSTERR .= $_;
  615.         }
  616.         }
  617.         if ($retcnt > $HOSTCNT) {
  618.         $HOSTCNT = $retcnt;
  619.         }
  620.         if ($? && 0xFF) {
  621.         &license_error();
  622.         }
  623.     } else {
  624.         $HOSTERR = "";
  625.         $HOSTCNT = 0;
  626.     }
  627.     if ($HOSTCNT < $count) {
  628.         $HOSTMAX = $HOSTCNT;
  629.         &license_error();
  630.     }
  631.     }
  632. }
  633.  
  634. sub license_error {
  635.     local($i) = $HOSTMAX;
  636.  
  637.     if ($i == 0) {
  638.     print STDERR "Error: no licenses available for roboinst.\n";
  639.     } elsif ($i == 1) {
  640.     print STDERR "Error: only 1 license available for roboinst.\n";
  641.     } else {
  642.     print STDERR "Error: only $i licenses available for roboinst.\n";
  643.     }
  644.     if ($HOSTERR) {
  645.     print STDERR $HOSTERR;
  646.     }
  647.  
  648.     print <<EOF
  649.  
  650. This product requires a license password, to obtain an Evaluation
  651. or Permanent license please visit our license request web page:
  652.  
  653.     http://www.sgi.com/Products/license.html
  654.  
  655.     or send a blank email message to:
  656.  
  657.     license\@sgi.com
  658.  
  659. In North America, Silicon Graphics' customers may request
  660. Permanent licenses by sending a facsimile to:
  661.  
  662.     (650) 390-0537
  663.  
  664.     or by calling our technical support hotline
  665.  
  666.     1-800-800-4SGI
  667.  
  668. If you are outside of North America or you are not a Silicon
  669. Graphics support customer then contact your local support provider.
  670.  
  671. Note: Permanent Licenses require verification of entitlement
  672. (i.e., Proof-of-Purchase).
  673. EOF
  674. }
  675.